package cn.yudao.ymcc.service.impl;

import cn.yudao.ymcc.config.RedisConfig;
import cn.yudao.ymcc.domain.Course;
import cn.yudao.ymcc.domain.CourseMarket;
import cn.yudao.ymcc.domain.KillActivity;
import cn.yudao.ymcc.domain.KillCourse;
import cn.yudao.ymcc.dto.KillOrderDto;
import cn.yudao.ymcc.dto.KillPrmDto;
import cn.yudao.ymcc.dto.UserInfoParamDto;
import cn.yudao.ymcc.mapper.KillCourseMapper;
import cn.yudao.ymcc.service.IKillActivityService;
import cn.yudao.ymcc.service.IKillCourseService;
import cn.yudao.ymcc.utils.AssertUtil;
import cn.yudao.ymcc.utils.CodeGenerateUtils;
import cn.yudao.ymcc.utils.SecurityGetUserInfoUtil;
import cn.yudao.ymcc.vo.Course2OrderVo;
import cn.yudao.ymcc.vo.CourseInfoVo;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.google.errorprone.annotations.Var;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author whale.jia
 * @since 2022-08-23
 */
@Service
public class KillCourseServiceImpl extends ServiceImpl<KillCourseMapper, KillCourse> implements IKillCourseService {

    @Autowired
    private IKillActivityService killActivityService;


    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    /**
    * @Title: add
    * @Description: 添加秒杀课程
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/8/23 15:02
    * @Parameters:
    * @Return
    */
    @Override
    public void add(KillCourse killCourse) {
        // 非空校验 -- JSR303
        Long courseId = killCourse.getCourseId();
        Long activityId = killCourse.getActivityId();
        // 判断当前课程是否存在此活动
        KillCourse killCourseTem = selectBycourseIdAndActivityId(courseId, activityId);
        AssertUtil.isNull(killCourseTem,"请勿重复添加课程");
        // 获取当前活动
        KillActivity killActivity = killActivityService.selectById(activityId);
        // 判断活动是否存在
        AssertUtil.isNotNull(killActivity,"活动不存在，搞我是吧");
        // 判断活动状态
        AssertUtil.isTrue(killActivity.getPublishStatus() == KillActivity.WAIT_PUBLICATION,"活动异常");
        // 给秒杀课程字段赋值
        killCourse.setCreateTime(new Date()); // 表单创建时间
        killCourse.setStartTime(killActivity.getBeginTime()); // 活动开始时间
        killCourse.setEndTime(killActivity.getEndTime()); // 活动结束时间
        killCourse.setTimeStr(killActivity.getTimeStr()); // 时间段
        // 保存数据库
        insert(killCourse);
    }

    /**
    * @Title: onlineAll
    * @Description: 获取redis的秒杀课程
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/8/24 9:58
    * @Parameters:
    * @Return
    */
    @Override
    public List<KillCourse> onlineAll() {
        // 获取redis中的所有秒杀课程--获取所有的大key
        Set<Object> keys = redisTemplate.keys("activity:*");
        // 通过key获取所有的value--秒杀课程内容
        List<KillCourse> killCourses = new ArrayList<>();
        keys.forEach(key ->{
            List values = redisTemplate.opsForHash().values(key);
            // 将集合转换为KillCourse类型
            killCourses.addAll(values);
        });
        return killCourses;

    }

    /**
    * @Title: onlineOne
    * @Description: 通过课程id和活动id从redis中获取某个商品信息
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/8/24 10:56
    * @Parameters:
    * @Return
    */
    @Override
    public KillCourse onlineOne(Long courseId, Long activityId) {
        KillCourse killCourse = (KillCourse)redisTemplate.opsForHash().get("activity:" + activityId, "killCourse:" + courseId);
        return killCourse;
    }

    /**
    * @Title: killOrder
    * @Description: 获取秒杀订单号--预创订单-减少库存（信号量）
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/8/24 12:41
    * @Parameters:
    * @Return
    */
    @Override
    public String killOrder(KillPrmDto dto) {
        // 获取秒杀课程id和活动id
        Long killCourseId = dto.getKillCourseId();
        Long killActivityId = dto.getKillActivityId();
        // 校验此商品是否存在
        KillCourse killCourse = onlineOne(killCourseId, killActivityId);
        AssertUtil.isNotNull(killCourse,"搞事是吧!!");
        // 检测用户有没有重复购买---待定
        // 检测活动时间是否在秒杀中--待定
        AssertUtil.isTrue(killCourse.getKilling(),"活动未开始");
        // 减少信号量-1
        String SemaphoreKey = killActivityId + ":" + killCourse.getId();
        RSemaphore semaphore = redissonClient.getSemaphore(SemaphoreKey);
        boolean issuccess = semaphore.tryAcquire(); // 尝试将信号量-1
        if (issuccess){
            // 通过自定义的方法获取userInfoParamDto对象得到security上下文对象中的用户信息
            UserInfoParamDto userInfoParamDto = SecurityGetUserInfoUtil.getUserInfoParamDto();
            Long loginId = userInfoParamDto.getId();
            // 填充欲创建订单数据
            KillOrderDto killOrderDto = new KillOrderDto();
            killOrderDto.setOrderNo(CodeGenerateUtils.generateOrderSn(4L)); // 订单号
            killOrderDto.setCourseId(killCourse.getCourseId()); // 课程id
            killOrderDto.setCourseName(killCourse.getCourseName()); // 课程名
            killOrderDto.setCoursePic(killCourse.getCoursePic()); // 封面
            killOrderDto.setTotalAmount(killCourse.getKillPrice()); // 价格
            killOrderDto.setUserId(loginId); // 用户id
            killOrderDto.setTotalCount(1);
            // 将数据存入redis中
            redisTemplate.opsForValue().set(killOrderDto.getOrderNo(),killOrderDto);
            return killOrderDto.getOrderNo();
        }else {
            return "手速加油练习，秒杀失败";
        }
    }

    /**
    * @Title: oneByOrder
    * @Description: 填充订单详情页数据
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/8/24 15:59
    * @Parameters:
    * @Return
    */
    @Override
    public CourseInfoVo oneByOrder(String orderNo) {
        // 非空校验
        AssertUtil.isNotEmpty(orderNo,"非法请求");
        // 获取购买的课程的订单信息
        Object tem = redisTemplate.opsForValue().get(orderNo);
        // 判断预创建订单存在
        AssertUtil.isNotNull(tem,"订单异常");
        KillOrderDto killOrder = (KillOrderDto) tem;
        // 填充数据到course
        Course course = new Course();
        course.setPic(killOrder.getCoursePic()); // 封面
        course.setName(killOrder.getCourseName()); // 课程名称
        CourseMarket courseMarket = new CourseMarket();
        courseMarket.setPrice(killOrder.getTotalAmount()); // 价格
        Course2OrderVo course2OrderVo = new Course2OrderVo(course,courseMarket);
        List<Course2OrderVo> course2OrderVos = new ArrayList<>();
        course2OrderVos.add(course2OrderVo);
        return new CourseInfoVo(course2OrderVos, courseMarket.getPrice());
    }

    /**
    * @Title: selectBycourseIdAndActivityId
    * @Description: 通过课程id和活动id获取对应的秒杀商品
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/8/23 15:06
    * @Parameters:
    * @Return
    */
    private KillCourse selectBycourseIdAndActivityId(Long courseId, Long activityId) {
        Wrapper<KillCourse> wrapper = new EntityWrapper<>();
        wrapper.eq("course_id", courseId).eq("activity_id",activityId);
        return selectOne(wrapper);
    }
}
